package com.spsoft.system.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.spsoft.core.config.VmsProperties;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.Base64;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.DESCrypt;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.entity.SysFunlist;
import com.spsoft.system.mapper.SysFunlistMapper;
import com.spsoft.system.model.vo.LoginUserVo;
import com.spsoft.system.model.vo.MenuVo;
import com.spsoft.system.model.vo.OrganVo;
import com.spsoft.system.model.vo.RefreshTokenVo;
import com.spsoft.system.service.SysLoginService;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class SysLoginServiceImpl implements SysLoginService {

   private final SysFunlistMapper sysFunlistMapper;

   private final RedisService redisService;

   private  final VmsProperties vmsProperties;

    private final RedissonClient redisson;

    @Override
    public Result<LoginUserVo> getMenu() {
        TokenUser tokenUser = SecurityUtils.getTokenUser();
        LoginUserVo loginUserVo = new LoginUserVo();
        loginUserVo.setUserInfo(tokenUser);
        loginUserVo.setButtons(new ArrayList<MenuVo>());
        List<SysFunlist> sysFunlists = sysFunlistMapper.selectByRoleId(tokenUser.getRoleId());
        Map<String,List<MenuVo>> dataMap = new HashMap<>();
        List<MenuVo> mainList = new ArrayList<>();
        if(sysFunlists != null && sysFunlists.size() >0){
           for (SysFunlist s : sysFunlists) {
               MenuVo m = new MenuVo();
               m.setId(s.getFunid());
               m.setName(s.getFunname());
               m.setPath("null".equals(s.getUrl())?"":s.getUrl());
               m.setCode(s.getMenuid());
               m.setType(Integer.toString(s.getFuntype()));
               //处理按钮权限
               if( s.getFuntype() !=null && s.getFuntype()==2) {
                   List<MenuVo> buttons = loginUserVo.getButtons();
                   buttons.add(m);
               }else {
                   if(dataMap.containsKey(s.getPrefun())){
                       dataMap.get(s.getPrefun()).add(m);
                   }else{
                       List<MenuVo> voList = new ArrayList<>();
                       voList.add(m);
                       dataMap.put(s.getPrefun(),voList);
                   }
                   //2000是顶级菜单
                   if("2000".equals(s.getPrefun())){
                       mainList.add(m);
                   }
               }
           }
        }
        List<MenuVo> menuList =new ArrayList<>();
        if(mainList.size() >0){
             menuList = getSubMenu(dataMap, mainList);
        }
        loginUserVo.setMenus(menuList);
        return Result.OK(loginUserVo);
    }


    /**
     *  第一个刷新token时，因为token时老系统生成， 这样TokenUser.getRefreshToken和refreshToken都相同 都是无值的
     *  生成新的refreshToken 和新的token 放入缓存，
     *  以后在刷新token时，先判断TokenUser.getRefreshToken和refreshToken是否一致，如果不一致，则返回错误
     *  如果一致， 生成新的refreshToken 和新的token 放入缓存，并返回新的refreshToken 和token
     * @param refreshToken
     * @return
     */
    @Override
    public Result<RefreshTokenVo> refreshToken(String refreshToken) {

        TokenUser t = SecurityUtils.getTokenUser();
        String token = SecurityUtils.getToken();
        String refreshTokenKey = null;
        log.info("refreshToken:{},t.getRefreshToken:{}",refreshToken,t.getRefreshToken());
        if (t != null
                && StringUtil.isNotEmpty(t.getDeptCode())
                && StringUtil.isNotEmpty(t.getUserCode())) {

            if(StringUtil.isNotEmpty(refreshToken) && refreshToken.equals(t.getRefreshToken())){
                refreshTokenKey =String.format(RedisConstant.REFRESH_TOKEN,t.getDeptCode(),t.getUserCode(),refreshToken);
                String retoken=redisService.getCacheObject(refreshTokenKey);
                if(retoken ==null  //缓存不存在
                        ||!token.equals(retoken) //缓存的token与当前token不一致
                        || !refreshToken.equals(t.getRefreshToken()) //刷新token与当前的刷新token不一致
                         ){
                    return Result.ERROR(ResponseEnum.REFRESH_TOKEN_INVALID);
                }

            } else if(StringUtil.isEmpty(refreshToken) && StringUtil.isNotEmpty(t.getRefreshToken()) ){
                return Result.ERROR(ResponseEnum.REFRESH_TOKEN_INVALID);
            }
            if(StringUtil.isEmpty(t.getRefreshToken())){
                //TODO 暂时注释， 后续修改，
//                String  oldKey=String.format(RedisConstant.OLD_TOKEN,t.getDeptCode(),t.getUserCode());
//                RSet<String> set = redisson.getSet(oldKey);
//                if(set.contains(token)){
//                    log.info("用户：{},oldToken:{}已经存在",t.getUserCode(),token);
//                    return Result.ERROR(ResponseEnum.REFRESH_TOKEN_INVALID);
//                }
//                boolean add = set.add(token);
//                if(add){
//                    set.expire(1, TimeUnit.DAYS);
//                }
//                log.info("用户：{},oldToken:{},放入缓存成功",t.getUserCode(),token);
            }



            String nrefreshToken = IdUtil.simpleUUID();
            t.setRefreshToken(nrefreshToken);
            t.setLoginTime(System.currentTimeMillis());
            String ntoken = SecurityUtils.getTokenUserToToken(t);
            if (ntoken != null) {
                //删除旧缓存
                if(refreshTokenKey!=null){
                    redisService.deleteObject(refreshTokenKey);
                }
               String key = String.format(RedisConstant.REFRESH_TOKEN, t.getDeptCode(), t.getUserCode(), nrefreshToken);
               //放入缓存
                redisService.setCacheObject(key, ntoken, vmsProperties.getRefreshTokenExpireTime(), TimeUnit.SECONDS);
                RefreshTokenVo r = new RefreshTokenVo(nrefreshToken, ntoken);
                log.info("用户：{},newRefreshToken:{},放入缓存成功",t.getUserCode(),nrefreshToken);
                return Result.OK(r);
            }
        }
        return Result.ERROR(ResponseEnum.LOGIN_ERROR);
    }

    private List<MenuVo> getSubMenu(Map<String, List<MenuVo>> dataMap, List<MenuVo> mainList) {

        if(mainList==null || mainList.size()==0){
            return new ArrayList<>();
        }
        List<MenuVo> retList = new ArrayList<>();
        for(MenuVo vo:mainList){
            if(dataMap.containsKey(vo.getId())){
                List<MenuVo> m = dataMap.get(vo.getId());
                dataMap.remove(vo.getId());
                List<MenuVo> subDepts=getSubMenu(dataMap,m);
                vo.setChildren(subDepts);
            }else{
                vo.setChildren(new ArrayList<>());
            }
            retList.add(vo);
        }
        return retList;

    }
}
